from __future__ import with_statement
from fabric.api import *
from fabric.contrib import files
import os
import posixpath
import pprint
from re import match
from functools import wraps
from fabric import state
from fabric import network
from fabric import operations




def upload(name, to=None, skip_unexistent=False, **kwargs):
    '''
    uploads a file to a target_url base on the file type.
    
    In the following example we upload a 'script' called setup-web2py-ubuntu.sh
    to the script target url. 

    uc_utils.upload('script','setup-web2py-ubuntu.sh',
                                     script_target_url,
                                     use_sudo=False)
    '''
    files.upload_template(file, to, env.conf, use_jinja=True,
                          **kwargs)

def _template_path(name):
    for dir in env.conf.TEMPLATE_PATHS:
        path = os.path.join(dir, name)
        if os.path.exists(path):
            return path

def _script_path(name):
    for dir in env.conf.SCRIPT_PATHS:
        path = os.path.join(dir, name)
        if os.path.exists(path):
            return path

def update_env():
    """
    Updates :attr:`env.conf` configuration with some defaults and converts
    it to state._AttributeDict (that's a dictionary subclass enabling attribute
    lookup/assignment of keys/values).

    Call :func:`update_env` at the end of each server-configuring function.

    ::

        from uc_deploy import *

        def my_site():
            env.hosts = ['my_site@example.com']
            env.conf = dict(
                DB_PASSWORD = 'password',
            )
            update_env()
    """
    assert len(env.hosts) == 1, "Multiple hosts in env.hosts are not supported now. (%s)" % env.hosts
    user, host, port = network.normalize(env.hosts[0])

    env.conf = getattr(env, 'conf', {})

    env.conf.setdefault('INSTANCE_NAME', user)
    env.conf.setdefault('PROJECT_PATH', '')

    HOME_DIR = '/home/%s' % user if user != 'root' else '/root'
    SRC_DIR = posixpath.join(HOME_DIR, 'src', env.conf['INSTANCE_NAME'])
    PROJECT_DIR = posixpath.join(SRC_DIR, env.conf['PROJECT_PATH']).rstrip('/')

    defaults = state._AttributeDict(
        HG_BRANCH='default',
        GIT_BRANCH='master',
        DB_NAME=env.conf['INSTANCE_NAME'],
        DB_USER='root',
        SUDO_USER='root',
        PROCESSES=1,
        THREADS=15,
        SERVER_NAME=host,
        SERVER_ADMIN='example@example.com',
        VCS='hg',

        PROJECT_PATH='',
        LOCAL_CONFIG='config.py',
        REMOTE_CONFIG_TEMPLATE='config.server.py',
        TEMPLATE_PATHS=['templates'],
        SCRIPT_PATHS=['scripts'],

        PIP_REQUIREMENTS_PATH='reqs',
        PIP_REQUIREMENTS='all.txt',
        PIP_REQUIREMENTS_ACTIVE='active.txt',

        # these options shouldn't be set by user
        HOME_DIR=HOME_DIR,
        ENV_DIR=posixpath.join(HOME_DIR, 'envs', env.conf['INSTANCE_NAME']),
        SRC_DIR=SRC_DIR,
        PROJECT_DIR=PROJECT_DIR,
        USER=user,
    )
    defaults.update(env.conf)

    env.conf = defaults

    if env.conf.DB_USER == 'root':
        if 'DB_ROOT_PASSWORD' in env.conf and 'DB_PASSWORD' in env.conf:
            msg = "DB_ROOT_PASSWORD and DB_PASSWORD must be the same because DB_USER is root"
            assert env.conf.DB_ROOT_PASSWORD == env.conf.DB_PASSWORD, msg
        else:
            # auto-fill the missing option
            password = env.conf.get('DB_ROOT_PASSWORD',
                                    env.conf.get('DB_PASSWORD', None))
            if password is not None:
                env.conf.DB_PASSWORD = env.conf.DB_ROOT_PASSWORD = password

    for vcs in ['git', 'hg', 'none']: # expand VCS name to full import path
        if env.conf.VCS == vcs:
            env.conf.VCS = 'uc_deploy_deploy.vcs.' + vcs
